package com.zy.ext.util;

import org.apache.ibatis.cache.CacheException;

import java.util.concurrent.*;

public class CacheLock {
  private long timeout;
  private final ConcurrentHashMap<Object, CountDownLatch> locks = new ConcurrentHashMap<>();


  private void acquireLock(Object key) {
    CountDownLatch newLatch = new CountDownLatch(1);
    while (true) {
      CountDownLatch latch = locks.putIfAbsent(key, newLatch);
      if (latch == null) {
        break;
      }
      try {
        if (timeout > 0) {
          boolean acquired = latch.await(timeout, TimeUnit.SECONDS);
          if (!acquired) {
            throw new CacheException(
              "Couldn't get a lock in " + timeout + " for the key " + key + " at the cache ");
          }
        } else {
          latch.await();
        }
      } catch (InterruptedException e) {
        throw new CacheException("Got interrupted while trying to acquire lock for key " + key, e);
      }
    }
  }

  private void releaseLock(Object key) {
    CountDownLatch latch = locks.remove(key);
    if (latch == null) {
      throw new IllegalStateException("Detected an attempt at releasing unacquired lock. This should never happen.");
    }
    latch.countDown();
  }

  public long getTimeout() {
    return timeout;
  }

  public void setTimeout(long timeout) {
    this.timeout = timeout;
  }

  public static void main(String[] args) throws InterruptedException {
    final int[] i = {0};
    CacheLock cacheLock = new CacheLock();
    cacheLock.setTimeout(10);



    ExecutorService executorService = Executors.newFixedThreadPool(10);
    for (int j = 0; j < 1000; j++) {
      executorService.execute(() -> {
        cacheLock.acquireLock("1");
        int i1 = i[0];
        i1++;
        i[0] =i1;
        cacheLock.releaseLock("1");
      });
    }
    System.out.println("i = " + i[0]);
    TimeUnit.DAYS.sleep(1);


  }
}
